package com.ordertracker.service;

import java.util.Date;
import java.util.HashMap;
import java.util.UUID;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ordertracker.Application;
import com.ordertracker.Session;
import com.ordertracker.client.ClientSession;
import com.ordertracker.dao.GeneralCrudDao;
import com.ordertracker.exception.NotAuthorizationException;
import com.ordertracker.persistent.constant.UserState;
import com.ordertracker.persistent.dictionary.ClientEmployee;
import com.ordertracker.persistent.dictionary.Employee;
import com.ordertracker.persistent.dictionary.User;
import com.ordertracker.protocol.ResponseAuthorization;
import com.ordertracker.to.TransferObjectFactory;
import com.ordertracker.util.DateUtils;
import com.sun.jersey.oauth.signature.OAuthParameters;

/**
 * Created by IntelliJ IDEA.
 * User: Andrey
 * Date: 09.01.13
 * Time: 2:06
 * To change this template use File | Settings | File Templates.
 */
@Service
public class AuthorizationService {

    private static Logger logger = Logger.getLogger(Application.class);

    private GeneralCrudDao crudDao;

    private TransferObjectFactory transferObjectFactory;

    @Resource(name = "tof")
    public void setTransferObjectFactory(TransferObjectFactory transferObjectFactory) {
        this.transferObjectFactory = transferObjectFactory;
    }

    @Resource(name = "crudDao")
    public void setCrudDao(GeneralCrudDao<User, Long> crudDao) {
        this.crudDao = crudDao;
    }
    
    @Transactional(readOnly = true)
    public ResponseAuthorization checkUser(final String login, final String pass, final String locale, final String timezone) throws NotAuthorizationException {
        HashMap<String, String> authMap = new HashMap<String, String>(2);
        authMap.put("login", login);
        final User user = (User) crudDao.findEqualByCriteria("login", login, User.class);

        if (null == user || !pass.equals(user.getPassword())) {
            NotAuthorizationException exception = new NotAuthorizationException("login/password not found !");
            logger.error("login/password not found !",exception);
            throw exception;
        }

        if (user.getUserState() != UserState.ACTIVE) {
            NotAuthorizationException exception = new NotAuthorizationException("Your account has "+ user.getUserState()+ " state");
            logger.error("Account for user: "+user.toString()+ " have state: "+user.getUserState(),exception);
            throw exception;

        }

        byte[] keyHash = com.sun.jersey.core.util.Base64.encode(user.getLogin());

        Session session = new Session();
        ClientSession clientSession = createClientSession(user, String.valueOf(keyHash), locale, timezone);

        OAuthParameters parameters = new OAuthParameters().consumerKey(String.valueOf(keyHash)).
                token(clientSession.getSessionToken()).signatureMethod("HMAC-SHA1");

        ResponseAuthorization responseAuthorization = new ResponseAuthorization(clientSession);

        ClientEmployee clientEmployee = getClientByUser(user);
        if (clientEmployee != null) {
            session.setClient(clientEmployee.getClient());
            responseAuthorization.setClient(transferObjectFactory.clientToDTO(clientEmployee.getClient()));
        }
        Employee employee = getEmployeeByUser(user);
        if (employee != null) {
            responseAuthorization.setEmployee(transferObjectFactory.employeeToDTO(employee));
            session.setEmployee(employee);
        }

        session.setSessionId(clientSession.getSessionToken());
        session.setSessionKey(parameters.getConsumerKey());
        session.setLocale(locale);
        session.setTimezone(timezone);
        session.setCreateDate(DateUtils.getCurrDate());
        session.setUser(user);

        session.setSessionId(parameters.getToken());
        clientSession.setSessionToken(parameters.getToken());


        Application.getApplication().getSessionCash().put(parameters.getToken(), session);
        return responseAuthorization;
    }

    @Transactional
    public ClientSession logout(ClientSession clientSession) {
        Session session = Application.getApplication().getSessionCash().remove(clientSession.getSessionToken());
        session = null;
        return clientSession;
    }

    private Employee getEmployeeByUser(User user) {
        return (Employee) crudDao.findEqualByCriteria("user", user, Employee.class);
    }

    private ClientEmployee getClientByUser(User user) {
        return  (ClientEmployee) crudDao.findEqualByCriteria("user", user, ClientEmployee.class);
    }

    private ClientSession createClientSession(User user, String consumerKey ,final String locale, final String timezone) {
        Date createSessionDate = new Date(System.currentTimeMillis());
        String token = generateToken(user.getLogin(), user.getPassword(), String.valueOf(System.currentTimeMillis()), "q1w2e3", "1q2w3e");
        com.ordertracker.entity.User userDto = transferObjectFactory.userToDTO(user);
        ClientSession clientSession = new ClientSession(token, consumerKey, "Q1jk4]%@fddo$fds=FDS".getBytes() ,userDto, createSessionDate, timezone, locale, new HashMap<String, String>());
        return clientSession;
    }

    private String generateToken(String ... args) {
        String str ="";
        for (int i =0 ; i < args.length; i++) {
            str+=args[i]+ (i==4 ? "" : "-");
        }
        return UUID.nameUUIDFromBytes(str.getBytes()).toString();
    }
}
